package com.jackrain.nea.utility;

import com.jackrain.nea.core.redis.CusRedisTemplate;
import com.jackrain.nea.util.RedisOpsUtil;

import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * 实现分布式锁
 */
public class RedisLocker {
    /**
     * 默认超时时间 1 天
     */
    private static final long DEFAULT_TIMEOUT_MILLISECONDS = 1 * 24 * 60 * 60 * 1000;
    /**
     * 锁的key的前缀(防止冲突)
     */
    private static final String KEY_PREFIX = "com.jackrain.nea.utility.RedisLocker:";
    /**
     * 当前锁的key
     */
    private final String key;
    /**
     * 当前锁的标记
     */
    private final String token;
    /**
     * 操作redis
     */
    private CusRedisTemplate<Object, Object> redisTemplate;

    /**
     * 创建一把使用redis实现的锁
     *
     * @param key 锁的key
     */
    public RedisLocker(String key) {
        if (key != null) {
            this.key = KEY_PREFIX + key;
        } else {
            this.key = null;
        }
        //创建随机标记
        this.token = UUID.randomUUID().toString();
    }

    /**
     * 默认锁定 1 天
     *
     * @return true上锁成功  false上锁失败
     */
    public boolean lock() {
        return lock(DEFAULT_TIMEOUT_MILLISECONDS);
    }

    /**
     * 指定时间上锁
     *
     * @param timeoutMilliseconds 锁定毫秒数
     * @return true上锁成功  false上锁失败
     */
    public boolean lock(long timeoutMilliseconds) {

        if (key == null) {
            return true;
        }
        if (redisTemplate == null) {
            redisTemplate = RedisOpsUtil.getStrRedisTemplate();
        }

        Boolean succeed = redisTemplate.opsForValue().setIfAbsent(key, token);

        if (succeed) {
            //设置成功
            redisTemplate.expire(key, timeoutMilliseconds, TimeUnit.MILLISECONDS);
            return true;
        }

        return isMine();
    }


    /**
     * 立即解锁
     *
     * @return
     */
    public boolean unLock() {
        return unLock(-1);
    }

    /**
     * 指定时间解锁
     *
     * @param delayMilliseconds
     * @return
     */
    public boolean unLock(long delayMilliseconds) {
        if (key == null) {
            return true;
        }
        if (isMine()) {
            if (delayMilliseconds <= 0) {
                redisTemplate.delete(key);
            } else {
                redisTemplate.expire(key, delayMilliseconds, TimeUnit.MILLISECONDS);
            }
            return true;
        }
        return false;
    }

    /**
     * 校验redis
     *
     * @return
     */
    public boolean isMine() {
        if (key == null || redisTemplate == null) {
            return false;
        }
        return token.equals(redisTemplate.opsForValue().get(key));
    }
}
